package com.formulas.component.extension.register;

import com.formulas.component.extension.*;
import jakarta.annotation.Resource;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

/**
 * 扩展点注册器
 * @author yiwannuofulasi
 * @date 2023/6/12 16:37
 */
@Component
public class ExtensionRegister {

    @Resource
    private ExtensionRepository extensionRepository;

    /**扩展文件命名**/
    public final static String EXTENSION_EXTPT_NAMING = "ExtPt";

    /**
     * 扩展点注册
     * @param extensionObject 扩展对象
     */
    public void doRegistration(ExtensionPointI extensionObject){
        Class<?> extensionClz = extensionObject.getClass();
        if (AopUtils.isAopProxy(extensionObject)) {
            extensionClz = ClassUtils.getUserClass(extensionObject);
        }
        Extension extensionAnn = AnnotationUtils.findAnnotation(extensionClz, Extension.class);
        BizScenario bizScenario = BizScenario.valueOf(extensionAnn.bizId(), extensionAnn.useCase(), extensionAnn.scenario());
        ExtensionCoordinate extensionCoordinate = new ExtensionCoordinate(calculateExtensionPoint(extensionClz), bizScenario.getUniqueIdentity());
        ExtensionPointI preVal = extensionRepository.getExtensionRepo().put(extensionCoordinate, extensionObject);
        if (preVal != null) {
            throw new RuntimeException("不允许重复注册 :" + extensionCoordinate);
        }
    }

    /**
     * 查找一个类的扩展点接口，并返回接口的名称
     * @param targetClz 查找目标
     * @return 扩展点接口名称
     */
    private String calculateExtensionPoint(Class<?> targetClz) {
        // 获取查找目标类的所有接口
        Class<?>[] interfaces = ClassUtils.getAllInterfacesForClass(targetClz);
        // 假设目标类没有其实现接口则抛出异常提示分配
        if (interfaces == null || interfaces.length == 0)
            throw new RuntimeException("请分配一个扩展点接口 for "+targetClz);
        for (Class intf : interfaces) {
            String extensionPoint = intf.getSimpleName();
            if (extensionPoint.contains(EXTENSION_EXTPT_NAMING))
                return intf.getName();
        }
        throw new RuntimeException("你的扩展点名称 for "+targetClz+" 不是有效的, 必须以此结尾 for "+ EXTENSION_EXTPT_NAMING);
    }

}
